﻿using NDF.Reflection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;

namespace NDF.Framework.Web
{
    /// <summary>
    /// 提供对 ASP.NET MVC 控制器的常用工具操作方法。
    /// </summary>
    public static class ControllerHelper
    {
        private static Type controllerBaseClass;
        private static string areasControllerNameSpaceToken;
        private static string controllerNameSpaceToken;

        /// <summary>
        /// 获取或设置用于表示 ASP.NET MVC 控制器基类的类型。
        /// </summary>
        public static Type ControllerBaseClass
        {
            get
            {
                if (controllerBaseClass == null)
                {
                    controllerBaseClass = typeof(Controller);
                }
                return controllerBaseClass;
            }
            set
            {
                controllerBaseClass = value;
            }
        }

        /// <summary>
        /// 获取或设置用于表示 ASP.NET MVC 区域控制器类型的命名空间前缀。
        /// </summary>
        public static string AreasControllerNameSpaceToken
        {
            get
            {
                if (areasControllerNameSpaceToken == null)
                {
                    areasControllerNameSpaceToken = "Areas";
                }
                return areasControllerNameSpaceToken;
            }
            set
            {
                areasControllerNameSpaceToken = value;
            }
        }

        /// <summary>
        /// 获取或设置用于表示 ASP.NET MVC 控制器类型的命名空间前缀。
        /// </summary>
        public static string ControllerNameSpaceToken
        {
            get 
            {
                if (controllerNameSpaceToken == null)
                {
                    controllerNameSpaceToken = "NDF";
                }
                return controllerNameSpaceToken;
            }
            set { controllerNameSpaceToken = value; }
        }


        /// <summary>
        /// 获取已加载的应用程序域执行上下文中所有包含 ASP.NET MVC 控制器的命名空间。
        /// </summary>
        /// <param name="withAreas">指示返回的数组中是否包含 ASP.NET MVC 区域控制器命名空间，默认值为 false。</param>
        /// <returns>已加载的应用程序域执行上下文中所有包含 ASP.NET MVC 控制器的命名空间。</returns>
        public static string[] GetControllerNamespaces(bool withAreas = false)
        {
            return GetControllerNamespaces(IsController, withAreas);
        }

        /// <summary>
        /// 获取已加载的应用程序域执行上下文中所有包含 ASP.NET MVC 控制器的命名空间。
        /// 该方法会获取已加载应用程序域执行上下文中所有的 ASP.NET MVC 控制器类型，然后将其命名空间组合成一个数组后执行去重操作并返回。
        /// </summary>
        /// <param name="isController">用于判断指定的类型 <see cref="System.Type"/> 是否是 ASP.NET MVC 控制器类型的委托方法。</param>
        /// <param name="withAreas">指示返回的数组中是否包含 ASP.NET MVC 区域控制器命名空间，默认值为 false。</param>
        /// <returns>已加载的应用程序域执行上下文中所有包含 ASP.NET MVC 控制器的命名空间所构成的一个数组。。</returns>
        public static string[] GetControllerNamespaces(Func<Type, bool> isController, bool withAreas = false)
        {
            var namespaces = GetControllers(isController).Map<Type, string>(t => t.Namespace).Distinct(StringComparer.CurrentCultureIgnoreCase);
            if (!withAreas)
            {
                namespaces = namespaces.Where(IsNotAreasNamespace);
            }
            return namespaces.ToArray();
        }






        /// <summary>
        /// 获取已加载的应用程序域执行上下文中所有的 ASP.NET MVC 控制器类型。
        /// </summary>
        /// <returns>已加载的应用程序域执行上下文中所有的 ASP.NET MVC 控制器类型 <see cref="System.Type"/> 所构成的一个数组。</returns>
        public static Type[] GetControllers()
        {
            return GetControllers(IsController);
        }

        /// <summary>
        /// 获取已加载的应用程序域执行上下文中所有的 ASP.NET MVC 控制器类型。
        /// </summary>
        /// <param name="isController">用于判断指定的类型 <see cref="System.Type"/> 是否是 ASP.NET MVC 控制器类型的委托方法。</param>
        /// <returns>已加载的应用程序域执行上下文中所有的 ASP.NET MVC 控制器类型 <see cref="System.Type"/> 所构成的一个数组。</returns>
        public static Type[] GetControllers(Func<Type, bool> isController)
        {
            return AssemblyHelper.GetPublicTypes().Where(isController).ToArray();
        }




        /// <summary>
        /// 判断指定的命名空间是否包含 ASP.NET MVC 控制器类型。
        /// </summary>
        /// <param name="nameSpace">指定的命名空间。</param>
        /// <returns>如果指定的命名空间是否包含 ASP.NET MVC 控制器类型，则返回 true，否则返回 false。</returns>
        public static bool IsControllerNamespace(string nameSpace)
        {
            return IsControllerNamespace(nameSpace, IsController);
        }

        /// <summary>
        /// 用指定的委托方法判断指定的命名空间是否包含 ASP.NET MVC 控制器类型。
        /// 该方法会获取指定命名空间下的所有类型，然后用 isController 委托方法循环校验每一个类型直到找到符合条件的项为止。
        /// </summary>
        /// <param name="nameSpace">指定的命名空间。</param>
        /// <param name="isController">用于判断指定的类型 <see cref="System.Type"/> 是否是 ASP.NET MVC 控制器类型的委托方法。</param>
        /// <returns>如果指定的命名空间是否包含 ASP.NET MVC 控制器类型，则返回 true，否则返回 false。</returns>
        public static bool IsControllerNamespace(string nameSpace, Func<Type, bool> isController)
        {
            return (string.IsNullOrWhiteSpace(ControllerNameSpaceToken) || (nameSpace != null && nameSpace.StartsWith(ControllerNameSpaceToken)))
                && TypeHelper.GetPublicTypes(nameSpace).Any(isController);
        }


        /// <summary>
        /// 判断一个 .NET Framework 命名空间是否是 ASP.NET MVC 区域控制器命名空间。
        /// 该方法与方法 <seealso cref="IsNotAreasNamespace"/> 的判断结果正好相反。
        /// </summary>
        /// <param name="nameSpace">.NET Framework 命名空间。</param>
        /// <returns>如果 nameSpace 是 ASP.NET MVC 区域控制器命名空间，则返回 true，否则返回 false。</returns>
        public static bool IsAreasNamespace(string nameSpace)
        {
            return !string.IsNullOrWhiteSpace(nameSpace) && nameSpace.Contains(AreasControllerNameSpaceToken);
        }

        /// <summary>
        /// 判断一个 .NET Framework 命名空间是否不为 ASP.NET MVC 区域控制器命名空间。
        /// 该方法与方法 <seealso cref="IsAreasNamespace"/> 的判断结果正好相反。
        /// </summary>
        /// <param name="nameSpace">.NET Framework 命名空间。</param>
        /// <returns>如果 nameSpace 是 ASP.NET MVC 区域控制器命名空间，则返回 false，否则返回 true。</returns>
        public static bool IsNotAreasNamespace(string nameSpace)
        {
            return !IsAreasNamespace(nameSpace);
        }

        /// <summary>
        /// 判断指定的类型对象是否是 ASP.NET MVC 控制器类型。
        /// </summary>
        /// <param name="c">指定的类型对象</param>
        /// <returns>如果指定的类型对象是否是 ASP.NET MVC 控制器类型，则返回 true，否则返回 false。</returns>
        public static bool IsController(Type c)
        {
            Guard.ArgumentNotNull(c, "c");
            return !c.IsAbstract && ControllerBaseClass.IsAssignableFrom(c)
                && (string.IsNullOrWhiteSpace(ControllerNameSpaceToken) || (c.Namespace != null && c.Namespace.StartsWith(ControllerNameSpaceToken)));
        }



    }
}
